home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / ftpd2.lha / ftpd2 / ftpserv.c < prev    next >
C/C++ Source or Header  |  1994-05-02  |  25KB  |  979 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <error.h>
  6. #include <stat.h>
  7. #include <dos.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/dir.h>
  10. #include <lineread.h>
  11. #include <sys/socket.h>
  12. #include <exec/memory.h>
  13. #include <dos/dostags.h>
  14. #include <libraries/multiuser.h>
  15.  
  16. #include <proto/exec.h>
  17. #include <proto/socket.h>
  18. #include <proto/multiuser.h>
  19. #include <proto/dos.h>
  20.  
  21. #include "ftp.h"
  22.  
  23. struct muBase *muBase;
  24. extern LONG server_socket;
  25.  
  26. char VersionTag[]="\0$VER: JoranFtpd 2.0 (14.12.93)";
  27.  
  28. char Hostname[40]="unknown";
  29. char Version[]="Joran 2.0";
  30.  
  31. char buf2[512];
  32. int tt1, tt2, tnw;
  33. int pdata=-1;                // For passive mode
  34. struct FileInfoBlock *PermChkFib;
  35. struct muUserInfo *UserInfo;
  36.  
  37. long gethostname(char *,long len);
  38.  
  39. struct LineRead *LineRead;
  40.  
  41. /* Command table */
  42. static char *commands[] = {
  43.     "user",
  44.     "acct",
  45.     "pass",
  46.     "type",
  47.     "list",
  48.     "cwd",
  49.     "dele",
  50.     "name",
  51.     "quit",
  52.     "retr",
  53.     "stor",
  54.     "port",
  55.     "nlst",
  56.     "pwd",
  57.     "xpwd",            /* For compatibility with 4.2BSD */
  58.     "mkd ",
  59.     "xmkd",            /* For compatibility with 4.2BSD */
  60.     "xrmd",            /* For compatibility with 4.2BSD */
  61.     "rmd ",
  62.     "stru",
  63.     "mode",
  64.     "pasv",            /* Pasive mode */
  65.     NULL
  66. };
  67.  
  68. /* Response messages */
  69. static char binwarn[]   = "100 Warning: File %s appears to be BINARY\n";
  70. static char sending[]   = "150 Open %s for %s %s (%ld Bytes)\n";
  71. static char recving[]   = "150 Open %s for %s %s\n";
  72.  
  73. static char typeok[]    = "200 Type %s OK\n";
  74. static char mkdok[]     = "200 MKD ok\n";
  75. static char portok[]    = "200 Port command okay\n";
  76. static char okay[]      = "200 Ok\n";
  77. static char banner[]    = "220 %s FTP Ready - v%s\n";
  78. static char bye[]       = "221 Goodbye!\n";
  79. static char rxok[]      = "226 File received OK\n";
  80. static char txok[]      = "226 File sent OK\n";
  81. static char logged[]    = "230 %s Logged in, %s\n";
  82. static char loggeda[]   = "230 %s Logged in as anonymous, %s\n";
  83. static char deleok[]    = "250 File deleted\n";
  84. static char pwdmsg[]    = "257 \"%s\" is current directory\n";
  85.  
  86. static char givepass[]  = "331 Enter Password\n";
  87. static char givepasa[]  = "331 Please enter your email address '<user-id>@<host-name>'\n";
  88.  
  89. static char lowmem[]    = "421 System overloaded, try again later\n";
  90. static char noconn[]    = "425 Data connection reset\n";
  91.  
  92. static char unsupp[]    = "500 Unsupported command or option\n";
  93. static char badcmd[]    = "500 Unknown command\n";
  94. static char only8[]     = "501 Only logical bytesize 8 supported\n";
  95. static char badtype[]   = "501 Unknown type \"%s\"\n";
  96. static char badport[]   = "501 Bad port syntax\n";
  97. static char unimp[]     = "502 Command not yet implemented\n";
  98. static char userfirst[] = "503 Login with USER first.\n";
  99. static char notlog[]    = "530 Please log in with USER and PASS\n";
  100. static char noperm[]    = "550 Permission denied\n";
  101. static char cantopen[]  = "550 Can't read file \"%s\": %s\n";
  102. static char delefail[]  = "550 Delete failed: %s\n";
  103. static char writerr[]   = "552 Write error: %s\n";
  104. static char nodir[]     = "553 Can't read directory \"%s\": %s\n";
  105. static char cantmake[]  = "553 Can't create \"%s\": %s\n";
  106. static char notyet[]    = "555 Try Later : Access '%2d:00-%2d:59 %s' only\n";
  107. static char nopasv[]        = "425 Can't open passive connection\n";
  108. static char pasvcon[]        =    "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\n";
  109.  
  110. void CloseAll(void)
  111. {
  112.     if(UserInfo) muFreeUserInfo(UserInfo);
  113.     if(PermChkFib) FreeDosObject(DOS_FIB,PermChkFib);
  114.     if(LineRead) FreeMem(LineRead,sizeof(struct LineRead));
  115.     if(muBase) CloseLibrary((struct Library *)muBase);
  116.     
  117.     if(LogLevel>=20) AddLog("FTPDeamon Stopped",FindTask(NULL));
  118. }
  119.  
  120. void InitAll(void)
  121. {
  122.     atexit(CloseAll);
  123.     
  124.     SetProgramName("JoranFtpd");
  125.     muBase=(struct muBase *)OpenLibrary(MULTIUSERNAME,MULTIUSERVERSION);
  126.     if(muBase && !(UserInfo=muAllocUserInfo())) exit(20);
  127.     gethostname(Hostname,sizeof(Hostname));
  128.     if(!(LineRead=AllocMem(sizeof(struct LineRead),MEMF_ANY))) exit(20);
  129.     initLineRead(LineRead,server_socket,RL_LFREQLF,RL_BUFSIZE);
  130.     if(!(PermChkFib=AllocDosObject(DOS_FIB,NULL))) exit(20);
  131. }
  132.  
  133. /* replace terminating end of line marker(s) with null */
  134. void rip(char *s)
  135. {
  136.     char *cp;
  137.     if((cp = strchr(s,'\n')) != NULL) *cp = '\0';
  138.     if((cp = strchr(s,'\r')) != NULL) *cp = '\0';
  139. }
  140.  
  141. /* This checks the current time is in a preset Time-Window before
  142.    allowing a user to login */
  143. int timewind(int argc,char *argv[],void *p)
  144. {
  145.     char *now;
  146.     long t;
  147.     char *t1, *t2;
  148.  
  149.     t1 = strdup(curftwin);
  150.     *(t1 + 2) = '\0';
  151.     tt1 = atoi(t1);
  152.  
  153.     t2 = strdup(curftwin+2);
  154.     *(t2 + 2) = '\0';
  155.     tt2 = atoi(t2);
  156.  
  157.     time(&t);
  158.     now = ctime(&t) + 11;
  159.     *(now + 2) = '\0';
  160.     tnw = atoi(now);
  161.  
  162.     if(tt1 > tt2) {
  163.         if(((tnw >= tt1) && (tnw <= 23)) ||
  164.            ((tnw <= tt2) && (tnw >= 0)))
  165.             return 0;        /* right in time */
  166.     } else {
  167.         if((tnw >= tt1) && (tnw <= tt2))
  168.             return 0;        /* right in time */
  169.     }
  170.  
  171.     return 1;
  172. }
  173.  
  174. /* Return 1 if the file operation is allowed, 0 otherwise */
  175. int permcheck(char *path,int perms,int op,char *file)
  176. {
  177.     BPTR l;
  178.     BYTE prot;
  179.     
  180.     if(file == NULL || path == NULL)
  181.         return 0;    /* Probably hasn't logged in yet */
  182.  
  183.     /* The target file must be under the user's allowed search path */
  184.     if(strncmp(file,path,strlen(path)) != 0)
  185.         return 0;
  186.  
  187.     prot=-1;
  188. //    if(muBase & perms&FTP_MULTIUSER)
  189. //    {
  190.         // Check default protection
  191. //        if(l=Lock(file,ACCESS_READ))
  192. //        {
  193. //            if(Examine(l,PermChkFib))
  194. //            {
  195. //                if(UserInfo->uid==muNOBODYUID)
  196. //                {
  197. //                    
  198. //                }
  199. //                if(UserInfo->uid==PermChkFib->fib_OwnerUID)
  200. //                {
  201. //                }
  202. //                if(UserInfo->gid==PermChkFib->fib_GroupUID)
  203. //                {
  204. //                }
  205. //                
  206. //            }
  207. //            UnLock(l);
  208. //        }
  209. //    }
  210.     
  211.     if(l=Lock(file,ACCESS_READ)) UnLock(l);
  212.     
  213.     switch(op){
  214.         case RETR_CMD:
  215.             /* User must have permission to read files */
  216.             if(perms&FTP_READ && prot&FIBF_READ)
  217.                 return 1;
  218.             return 0;
  219.         case DELE_CMD:
  220.         case RMD_CMD:
  221.             /* User must have permission to (over)write files */
  222.             if(perms&FTP_WRITE && prot&FIBF_DELETE)
  223.                 return 1;
  224.             return 0;
  225.         case STOR_CMD:
  226.         case MKD_CMD:
  227.             /* User must have permission to (over)write files, or permission
  228.              * to create them if the file doesn't already exist
  229.              */
  230.             if(!l && perms&FTP_CREATE) return 1;
  231.             if(l && perms&FTP_WRITE && prot&FIBF_DELETE)
  232.                 return 1;
  233.             return 0;
  234.     }
  235.     return 0;    /* "can't happen" -- keep lint happy */
  236. }
  237.  
  238. /* Subroutine for logging in the user whose name is name and
  239.    password is pass.  The buffer path should be long enough to
  240.    keep a line from the userfile.  If pwdignore is true, the
  241.    password check will be overridden.  The return value is the
  242.    permissions field or -1 if the login failed.  Path is set to
  243.    point at the path field, and pwdignore will be true if no
  244.    particular password was needed for this user.
  245.  */
  246. int userlogin(char *name,char *pass,char **path,int len,int *pwdignore)
  247. {
  248.     char *cp,*cp1;
  249.     FILE *fp;
  250.     char *rest = NULL;
  251.     int anony, perm;
  252.     int unknown=FALSE;
  253.  
  254.     *pwdignore=!strcmp("ftp",name);
  255.     anony = *pwdignore;
  256.  
  257.     if((fp = fopen(Userfile,"r")) == NULL) return -1; /* Userfile doesn't exist */
  258.         
  259.     while(fgets(*path,len,fp),!feof(fp))
  260.     {
  261.         if(*path[0] == '#') continue;    /* Comment */
  262.         if((cp=strchr(*path,' '))==NULL) continue; /* Bogus entry */
  263.         *cp++ = '\0'; /* Now points to password */
  264.         
  265.         if(stricmp(name,*path)==0) break; /* Found user name */
  266.         if(stricmp("rest",*path)==0) rest=strdup(cp); /* remember default entry */
  267.     }
  268.     unknown=feof(fp);
  269.     if((rest==NULL) && unknown) 
  270.     {
  271.         /* User not in file, nor was anonymous */
  272.         fclose(fp);
  273.         return -1;
  274.     }
  275.      if(unknown)
  276.     {
  277.         /* restore default entry */
  278.         strcpy(cp = *path, rest);
  279.     }
  280.     fclose(fp);
  281.     
  282.     /* Look for space after password field in file */
  283.     if((cp1 = strchr(cp,' ')) == NULL) return -1; /* Invalid file entry */
  284.         
  285.     *cp1++ = '\0';    /* Now points to path field */
  286.     if(strcmp(cp,"*")!=0)
  287.     {
  288.         if(strcmp(cp,pass)!=0) return -1; /* Password required, but wrong one given */
  289.     }
  290.     if((cp = strchr(cp1,' ')) == NULL) return -1; /* Permission field missing */
  291.         
  292.     *cp++ = '\0';    /* now points to permission field */
  293.     perm = atoi(cp);
  294.     
  295.     if(unknown && (!muBase || !perm&FTP_MULTIUSER)) return -1;
  296.     
  297.     if(muBase && perm&FTP_MULTIUSER)
  298.     {
  299.         strncpy(UserInfo->UserID,name,muUSERIDSIZE);
  300.         if(!muGetUserInfo(UserInfo,muKeyType_UserID))
  301.         {
  302.             if(LogLevel>=10) AddLog("Unknown User \"%s\"",name);
  303.             return -1;
  304.         }
  305.         if(!muLogin(
  306.             muT_UserID,UserInfo->UserID,
  307.             muT_Password,anony?"":pass,
  308.             TAG_DONE
  309.         ))
  310.         {
  311.             if(LogLevel>=10) AddLog("Wrong password for \"%s\"",UserInfo->UserID);
  312.             return -1;
  313.         }
  314.     }
  315.     
  316. /*
  317.  *  Well, on the Amiga, a file can be referenced by many names:
  318.  *  device names (DF0:) or volume names (My_Disk:).  This hunk of code
  319.  *  passed the pathname specified in the ftpusers file, and gets the
  320.  *  absolute path copied into the user's buffer.  We really should just
  321.  *  allocate the buffer and return a pointer to it, since the caller
  322.  *  really doesn't have a good idea how long the path string is..
  323.  */
  324.     if(cp1[0]=='*') cp1=strdup("");
  325.     else cp1=pathname("",cp1);
  326.     
  327.     if (cp1) strcpy(*path, cp1);
  328.     else **path = '\0';
  329.     free(cp1);
  330.     
  331.     /* Finally return the permission bits */
  332.     return perm;
  333. }
  334.  
  335. /* Attempt to log in the user whose name is in ftp->username and password
  336.  * in pass
  337.  */
  338. static void ftplogin(struct ftpserv *ftp,char *pass)
  339. {
  340.     long t;
  341.     char *path,buf2[77],*cp,*cp1;
  342.     int anony = 0;
  343.     FILE *fp;
  344.  
  345.     path = malloc(200);
  346.     if((ftp->perms=userlogin(ftp->username,pass,&path,200,&anony)) == -1)
  347.     {
  348.         usprintf(ftp->control,noperm);
  349.         free(path);
  350.         return;
  351.     }
  352.     /* Set up current directory and path prefix */
  353.     if(*path) ftp->cd=strdup(path);
  354.     else
  355.     {
  356.         if(muBase) ftp->cd=pathname(UserInfo->HomeDir,"");
  357.         else ftp->cd=pathname(":","");
  358.     }
  359.     ftp->path = strdup(path);
  360.     free(path);
  361.  
  362.     sprintf(buf2,"%sFTP.After",SignOn);
  363.     if((fp = fopen(buf2,"r")) != NULL)
  364.     {
  365.         sendfile(fp,ftp->control,ASCII_TYPE,0);
  366.         fclose(fp);
  367.     }
  368.  
  369.     time(&t);
  370.     cp = ctime(&t);
  371.     if((cp1 = strchr(cp,'\n')) != NULL) *cp1 = '\0';
  372.  
  373.     if(!anony)
  374.     {
  375.         usprintf(ftp->control,logged,ftp->username,cp);
  376.         if(LogLevel>=15) AddLog("%s logged in",ftp->username);
  377.     } 
  378.     else 
  379.     {
  380.         usprintf(ftp->control,loggeda,
  381.             strcmp(ftp->username,"ftp") ? 
  382.             ftp->username : "",cp);
  383.         if(LogLevel>=15) AddLog("%s logged in, ID %s",ftp->username,pass);
  384.     }
  385. }        
  386.  
  387. static int sendit(struct ftpserv *ftp,char *command,char *file)
  388. {
  389.     long total;
  390.     struct sockaddr_in dport;
  391.     struct stat stb;
  392.  
  393.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  394.     dport.sin_family=AF_INET;
  395.     dport.sin_addr.s_addr=INADDR_ANY;
  396.     dport.sin_port=IPPORT_FTPD;
  397.     bind(ftp->data,(struct sockaddr *)&dport,sizeof(struct sockaddr_in));
  398.     
  399.     stat(file,&stb);
  400.     usprintf(ftp->control,sending,file,ftp->type ? "BINARY" : "ASCII",command,stb.st_size);
  401.     if(connect(ftp->data,(struct sockaddr *)&ftp->port,sizeof(struct sockaddr_in)) == -1){
  402.         fclose(ftp->fp);
  403.         ftp->fp = NULL;
  404.         CloseSocket(ftp->data);
  405.         ftp->data = -1;
  406.         ftp->pdata = -1;
  407.         usprintf(ftp->control,noconn);
  408.         return -1;
  409.     }
  410. //#ifdef FTPTDISC
  411.     /* Turn of the timeout timer here, some ftp's could
  412.      * take a long time with sloooow packet channels - WG7J
  413.      */
  414. //    stop_timer(&ftp->tdisc);
  415. //#endif
  416.     /* Do the actual transfer */
  417.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  418.  
  419. //#ifdef FTPTDISC
  420.     /* And turn it back on now */
  421. //    start_timer(&ftp->tdisc);
  422. //#endif
  423.     if(total == -1)
  424.     {
  425.         /* An error occurred on the data connection */
  426.         usprintf(ftp->control,noconn);
  427.         shutdown(ftp->data,2);    /* Blow away data connection */
  428.     } else usprintf(ftp->control,txok);
  429.  
  430.     fclose(ftp->fp);
  431.     ftp->fp = NULL;
  432.     CloseSocket(ftp->data);
  433.     ftp->data = -1;
  434.     ftp->pdata = -1;
  435.     if(total == -1) return -1;
  436.     else return 0;
  437. }
  438.  
  439. int recvit(struct ftpserv *ftp,char *command,char *file)
  440. {
  441.     struct sockaddr_in dport;
  442.     long total;
  443.  
  444.     ftp->data=socket(AF_INET,SOCK_STREAM,0);
  445.     dport.sin_family=AF_INET;
  446.     dport.sin_addr.s_addr=INADDR_ANY;
  447.     dport.sin_port = IPPORT_FTPD;
  448.     bind(ftp->data,(struct sockaddr *)&dport,sizeof(struct sockaddr_in));
  449.     usprintf(ftp->control,recving,file,ftp->type?"BINARY":"ASCII",command);
  450.     if(connect(ftp->data,(struct sockaddr *)&ftp->port,sizeof(struct sockaddr_in)) == -1)
  451.     {
  452.         fclose(ftp->fp);
  453.         ftp->fp = NULL;
  454.         CloseSocket(ftp->data);
  455.         ftp->data = -1;
  456.         ftp->pdata = -1;
  457.         usprintf(ftp->control,noconn);
  458.         return -1;
  459.     }
  460.     
  461. //#ifdef FTPTDISC
  462.     /* Turn of the timeout timer here; some ftp's could
  463.      * take a long time with sloooow packet channels - WG7J
  464.      */
  465. //    stop_timer(&ftp->tdisc);
  466. //#endif
  467.  
  468.     /* Do the actual transfer */
  469.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  470.  
  471. //#ifdef FTPTDISC
  472.     /* And turn it back on now */
  473. //    start_timer(&ftp->tdisc);
  474. //#endif
  475.  
  476.     if(total == -1)
  477.     {
  478.         /* An error occurred while writing the file */
  479.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  480.         shutdown(ftp->data,2);    /* Blow it away */
  481.     } 
  482.     else 
  483.     {
  484.         usprintf(ftp->control,rxok);
  485.         CloseSocket(ftp->data);
  486.     }
  487.     ftp->data = -1;
  488.     ftp->pdata = -1;
  489.     fclose(ftp->fp);
  490.     ftp->fp = NULL;
  491.     if(total == -1) return -1;
  492.     else return 0;
  493. }
  494.  
  495. static int pport(struct sockaddr_in *sock,char *arg)
  496. {
  497.     int n;
  498.     int i;
  499.  
  500.     n = 0;
  501.     for(i=0;i<4;i++)
  502.     {
  503.         n = atoi(arg) + (n << 8);
  504.         if((arg = strchr(arg,',')) == NULL) return -1;
  505.         arg++;
  506.     }
  507.     sock->sin_addr.s_addr = n;
  508.     n = atoi(arg);
  509.     if((arg = strchr(arg,',')) == NULL)    return -1;
  510.     arg++;
  511.     n = atoi(arg) + (n << 8);
  512.     sock->sin_port = n;
  513.     return 0;
  514. }
  515.  
  516. FILE *dir(char *path,int full)
  517. {
  518.    int ftotal=0, fnumbr=0;
  519.    BPTR FrameLock_p;
  520.     struct FileInfoBlock *fib_p;
  521.    FILE *f;
  522.     char wildcard[40],*p=NULL;
  523.     char parsecard[82];
  524.  
  525.     if(strchr(path,'*') || strchr(path,'?')) p=FilePart(path);
  526.     if(p)
  527.     {
  528.         strncpy(wildcard,p,sizeof(wildcard));
  529.         wildcard[sizeof(wildcard)-1]='\0';
  530.         p=PathPart(path);
  531.         if(p) *p='\0';
  532.     } else strcpy(wildcard,"*");
  533.     
  534.     if(ParsePatternNoCase(wildcard,parsecard,sizeof(parsecard))<=0) return NULL;
  535.  
  536.    if((f=tmpfile())==NULL) return NULL;
  537.     
  538.     if(FrameLock_p=Lock(path,ACCESS_READ))
  539.     {
  540.         if (fib_p=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
  541.         {
  542.             if(Examine(FrameLock_p,fib_p))
  543.             {
  544.                 if(fib_p->fib_DirEntryType<0)
  545.                     fprintf(f,"You can only use this command with a Directory Name\n");
  546.                 else
  547.                 {
  548.                     if(full)    fprintf(f,"    Size  File/Dir Name      Comment\n");
  549.                     while(ExNext(FrameLock_p,fib_p))
  550.                     {
  551.                         if(MatchPatternNoCase(parsecard,fib_p->fib_FileName))
  552.                         {
  553.                             if(full)
  554.                             {
  555.                                 if(fib_p->fib_DirEntryType>0)
  556.                                 {
  557.                                     fprintf(f,"    (Dir) ");
  558.                                 }
  559.                                 else if(fib_p->fib_Size == 0)
  560.                                 {
  561.                                     fprintf(f,"  (empty) ");
  562.                                 }
  563.                                 else
  564.                                 {
  565.                                     ftotal=ftotal+fib_p->fib_Size;
  566.                                     fnumbr++; 
  567.                                     fprintf(f,"%8d  ",fib_p->fib_Size);
  568.                                 }
  569.                             
  570.                                 fprintf(f,"%-16s", fib_p->fib_FileName);
  571.                                 fprintf(f,strlen(fib_p->fib_Comment) ? " : %-30s\n" : "\n",
  572.                                     fib_p->fib_Comment);
  573.                             }
  574.                             else if(fib_p->fib_DirEntryType<0) fprintf(f,"%s\n", fib_p->fib_FileName);
  575.                         }
  576.                     }
  577.                     if(full)
  578.                         fprintf(f, "Directory %s : %d Bytes : %d Files\n", path, ftotal, fnumbr);
  579.                 }
  580.             }
  581.             FreeMem(fib_p,sizeof(struct FileInfoBlock));
  582.         }
  583.         UnLock(FrameLock_p);
  584.    }
  585.     
  586.     rewind(f);
  587.  
  588.     return f;    
  589. }
  590.  
  591. FILE *extdir(char *arg)
  592. {
  593.     BPTR f;
  594.     FILE *fp;
  595.     char fn[30];
  596.     
  597.     sprintf(fn,"T:JoranFtpd%08X",FindTask(NULL));
  598.     
  599.     if(*arg) sprintf(buf2,ArgDirCommand,arg);
  600.     else sprintf(buf2,DefDirCommand,arg);
  601.     if(LogLevel>=30) AddLog("%s",buf2);
  602.     if(f=Open(fn,MODE_NEWFILE))
  603.     {
  604.         SystemTags(buf2,
  605.             SYS_Output,f,
  606.             TAG_DONE
  607.         );
  608.         Close(f);
  609.         if(fp=fopen(fn,"r")) return fp;
  610.     }
  611.     
  612.     return NULL;
  613. }
  614.  
  615. /* Note: a response of 425 is not mentioned as a possible response to the
  616.  * PASV command in RFC959. However, it has been blessed as a legitimate
  617.  * response by Jon Postel in a telephone conversation with Rick Adams on 25
  618.  * Jan 89. */
  619. void passive(struct ftpserv *ftp)
  620. {
  621.     LONG len;
  622.     register char *p,*a;
  623.  
  624.     ftp->pdata = socket(AF_INET, SOCK_STREAM, 0);
  625.     if (ftp->pdata < 0) {
  626.         usprintf(ftp->control,nopasv);
  627.         return;
  628.     }
  629.     ftp->pasv = ftp->port;
  630.     ftp->pasv.sin_port = 0;
  631.     // (void) seteuid((uid_t) 0);
  632.     if (bind(ftp->pdata, (struct sockaddr *) &ftp->pasv, sizeof(ftp->pasv)) < 0) {
  633.         // (void) seteuid((uid_t) pw->pw_uid);
  634.         goto pasv_error;
  635.     }
  636.     //(void) seteuid((uid_t) pw->pw_uid);
  637.     len = sizeof(ftp->pasv);
  638.     if (getsockname(ftp->pdata, (struct sockaddr *) &ftp->pasv, &len) < 0)
  639.         goto pasv_error;
  640.     if (listen(ftp->pdata, 1) < 0)
  641.         goto pasv_error;
  642.     a = (char *) &ftp->pasv.sin_addr;
  643.     p = (char *) &ftp->pasv.sin_port;
  644.  
  645. #define UC(b) (((int) b) & 0xff)
  646.  
  647.     usprintf(ftp->control,pasvcon,
  648.         UC(a[0]),UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  649.     return;
  650.  
  651.     pasv_error:
  652.         CloseSocket(ftp->pdata);
  653.         ftp->pdata = -1;
  654.         usprintf(ftp->control,nopasv);
  655.     return;
  656. }
  657.  
  658. main()
  659. {
  660.     struct ftpserv ftp;
  661.     FILE *fp;
  662.     long l,cnt;
  663.     char *buf,*arg;
  664.     char **cmdp,*p;
  665.     char *file,*mode;
  666.     fd_set readfds;
  667.     
  668.     AddLog("FTPDeamon Initialising");
  669.     
  670.     if(server_socket==-1) exit(20);
  671.     
  672.     InitAll();
  673.     ReadConfig();
  674.     
  675.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  676.     ftp.data=-1;
  677.     ftp.pdata=-1;
  678.     ftp.control=server_socket;
  679.     l=sizeof(struct sockaddr_in);
  680.     getpeername(server_socket,(struct sockaddr *)&ftp.port,&l);
  681.     ftp.port.sin_port=IPPORT_FTPD;
  682.     
  683.     if(LogLevel>=20) AddLog("FTPDeamon started",FindTask(NULL));
  684.     
  685.     sprintf(buf2,"%sFTP.Before",SignOn);
  686.     if((fp=fopen(buf2,"r"))!=NULL)
  687.     {
  688.         sendfile(fp,server_socket,ASCII_TYPE,0);
  689.         fclose(fp);
  690.     }
  691.  
  692.     usprintf(server_socket,banner,Hostname,Version);
  693.  
  694.     FD_ZERO(&readfds);
  695.     
  696.     for(;;)
  697.     {
  698.        FD_SET(server_socket,&readfds);
  699.        if (select(server_socket+1,&readfds,NULL,NULL,NULL)<0) break;
  700.        if(!FD_ISSET(server_socket,&readfds)) continue;
  701.    
  702.        cnt=lineRead(LineRead);
  703.        
  704.        if(cnt==0) continue;        // EOF
  705.        if(cnt==-1)
  706.        {
  707.            if(LineRead->rl_Line==NULL) goto finish;
  708.            continue;
  709.        }
  710.     
  711.        buf=LineRead->rl_Line;
  712.        rip(buf);
  713.         
  714.         AddLog("%s",buf);
  715.     
  716.        /* Find command in table; if not present, return syntax error */
  717.        for(cmdp=commands;*cmdp != NULL;cmdp++)
  718.            if(strnicmp(*cmdp,buf,strlen(*cmdp)) == 0)
  719.                break;
  720.        if(*cmdp == NULL){
  721.            usprintf(ftp.control,badcmd);
  722.            continue;
  723.        }
  724.        /* Allow only USER, PASS, QUIT before logging in */
  725.        if(ftp.cd == NULL || ftp.path == NULL){
  726.            switch(cmdp-commands){
  727.            case USER_CMD:
  728.            case PASS_CMD:
  729.            case QUIT_CMD:
  730.                break;
  731.            default:
  732.                usprintf(ftp.control,notlog);
  733.                continue;
  734.            }
  735.        }
  736.        arg = &buf[strlen(*cmdp)];
  737.        while(*arg == ' ') arg++;
  738.            
  739.        switch(cmdp-commands)
  740.        {
  741.            case USER_CMD:
  742.                if(timewind(NULL,NULL,NULL)) {
  743.                    usprintf(ftp.control,notyet,tt1,tt2,
  744.                        ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  745.                    goto finish;
  746.                }
  747.                free(ftp.username);
  748.                if(!strcmp("anonymous",arg)) ftp.username=strdup("ftp");
  749.                else ftp.username=strdup(arg);
  750.                if(!stricmp("ftp",ftp.username))    usprintf(ftp.control,givepasa);
  751.                else usprintf(ftp.control,givepass);
  752.                break;
  753.            case TYPE_CMD:
  754.                switch(arg[0])
  755.                {
  756.                    case 'A':
  757.                    case 'a':    /* Ascii */
  758.                        ftp.type = ASCII_TYPE;
  759.                        usprintf(ftp.control,typeok,arg);
  760.                        break;
  761.                    case 'l':
  762.                    case 'L':
  763.                        while(*arg != ' ' && *arg != '\0') arg++;
  764.                        if(*arg == '\0' || *++arg != '8')
  765.                        {
  766.                            usprintf(ftp.control,only8);
  767.                            break;
  768.                        }
  769.                        ftp.type = LOGICAL_TYPE;
  770.                        ftp.logbsize = 8;
  771.                        usprintf(ftp.control,typeok,arg);
  772.                        break;
  773.                    case 'B':
  774.                    case 'b':    /* Binary */
  775.                    case 'I':
  776.                    case 'i':    /* Image */
  777.                        ftp.type = IMAGE_TYPE;
  778.                        usprintf(ftp.control,typeok,arg);
  779.                        break;
  780.                    default:    /* Invalid */
  781.                        usprintf(ftp.control,badtype,arg);
  782.                        break;
  783.                }
  784.                break;
  785.            case QUIT_CMD:
  786.                usprintf(ftp.control,bye);
  787.                goto finish;
  788.            case RETR_CMD:
  789.                if(timewind(NULL,NULL,NULL))
  790.                {
  791.                    usprintf(ftp.control,notyet,tt1,tt2,
  792.                        ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  793.                    goto finish;
  794.                }
  795.                file=pathname(ftp.cd,arg);
  796.                switch(ftp.type) {
  797.                    case IMAGE_TYPE:
  798.                    case LOGICAL_TYPE:
  799.                        mode = "rb";
  800.                        break;
  801.                    case ASCII_TYPE:
  802.                        mode = "r";
  803.                        break;
  804.                }
  805.                if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
  806.                     usprintf(ftp.control,noperm);
  807.                else if((ftp.fp = fopen(file,mode)) == NULL)
  808.                    usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  809.                else
  810.                {
  811.                    if(LogLevel>=10) AddLog("RETR %s by %s",file,ftp.username);
  812.                    if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  813.                        usprintf(ftp.control,binwarn,file);
  814.                    }
  815.                    sendit(&ftp,"RETR",file);
  816.                }
  817.                free(file);
  818.                break;
  819.            case STOR_CMD:
  820.                if(timewind(NULL,NULL,NULL)) {
  821.                    usprintf(ftp.control,notyet,tt1,tt2,
  822.                        ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  823.                    goto finish;
  824.                }
  825.                file = pathname(ftp.cd,arg);
  826.                switch(ftp.type){
  827.                    case IMAGE_TYPE:
  828.                    case LOGICAL_TYPE:
  829.                        mode = "wb";
  830.                        break;
  831.                    case ASCII_TYPE:
  832.                        mode = "w";
  833.                        break;
  834.                }
  835.                if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file))
  836.                     usprintf(ftp.control,noperm);
  837.                else if((ftp.fp = fopen(file,mode)) == NULL)
  838.                    usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  839.                else 
  840.                {
  841.                    if(LogLevel>=5) AddLog("STOR %s by %s",file,ftp.username);
  842.                    recvit(&ftp,"STOR",file);
  843.                }
  844.                free(file);
  845.                break;
  846.            case PORT_CMD:
  847.                if(pport(&ftp.port,arg) == -1) usprintf(ftp.control,badport);
  848.                else usprintf(ftp.control,portok);
  849.                break;
  850.            case LIST_CMD:
  851.                if(DefDirCommand && ArgDirCommand && !(ftp.perms&FTP_NOEXTDIR))
  852.                {
  853.                    /* User external dir-command, you lose some protection when
  854.                       using this option */
  855.                    if(chdir(ftp.cd)) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  856.                    else if((ftp.fp=extdir(arg))==NULL) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  857.                    else     sendit(&ftp,"LIST",DefDirCommand);
  858.                }
  859.                else
  860.                {
  861.                    file = pathname(ftp.cd,arg);
  862.                    if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)) usprintf(ftp.control,noperm);
  863.                    else if((ftp.fp = dir(file,1)) == NULL) usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  864.                    else sendit(&ftp,"LIST",file);
  865.                    free(file);
  866.                }
  867.                break;
  868.            case NLST_CMD:
  869.                file = pathname(ftp.cd,arg);
  870.                if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
  871.                    usprintf(ftp.control,noperm);
  872.                else if((ftp.fp = dir(file,0)) == NULL)
  873.                    usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  874.                else sendit(&ftp,"NLST",file);
  875.                free(file);
  876.                break;
  877.            case PASS_CMD:
  878.                if(ftp.username == NULL) usprintf(ftp.control,userfirst);
  879.                else
  880.                {
  881.                    if(!strcmp(arg,"anonymous")) arg="ftp";
  882.                    ftplogin(&ftp,arg);
  883.                }
  884.                break;
  885.            case CWD_CMD:
  886.                if(!strncmp(arg,"..",2)) arg="/";
  887.                file = pathname(ftp.cd,arg);
  888.                if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file))
  889.                {
  890.                     usprintf(ftp.control,noperm);
  891.                    free(file);
  892.                } 
  893.                else if(access(file,0) == 0)
  894.                {    /* See if it exists */
  895.                    /* Succeeded, record in control block */
  896.                    free(ftp.cd);
  897.                    ftp.cd = file;
  898.                    sprintf(buf2,"%s/FTP.Dir",file);
  899.                    if((fp=fopen(buf2,"r"))!=NULL) 
  900.                    {
  901.                        sendfile(fp,server_socket,ASCII_TYPE,0);
  902.                        fclose(fp);
  903.                    }
  904.                    usprintf(ftp.control,pwdmsg,file);
  905.                } 
  906.                else 
  907.                {
  908.                    /* Failed, don't change anything */
  909.                    usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  910.                    free(file);
  911.                }
  912.                break;
  913.            case XPWD_CMD:
  914.            case PWD_CMD:
  915.                usprintf(ftp.control,pwdmsg,ftp.cd);
  916.                break;
  917.            case XMKD_CMD:
  918.            case MKD_CMD:
  919.                file = pathname(ftp.cd,arg);
  920.                if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file))
  921.                    usprintf(ftp.control,noperm);
  922.                else if(mkdir(file) == 0)
  923.                {
  924.                    if(LogLevel>=5) AddLog("MKD %s by %s",file,ftp.username);
  925.                    usprintf(ftp.control,mkdok);
  926.                } 
  927.                else usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  928.                free(file);
  929.                break;
  930.            case XRMD_CMD:
  931.            case RMD_CMD:
  932.                file = pathname(ftp.cd,arg);
  933.                if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file))
  934.                     usprintf(ftp.control,noperm);
  935.                else if(rmdir(file) == 0)
  936.                {
  937.                    if(LogLevel>=5) AddLog("RMD %s by %s",file,ftp.username);
  938.                    usprintf(ftp.control,deleok);
  939.                } 
  940.                else usprintf(ftp.control,delefail,sys_errlist[errno]);
  941.                free(file);
  942.                break;
  943.            case ACCT_CMD:        
  944.                usprintf(ftp.control,unimp);
  945.                break;
  946.            case STRU_CMD:
  947.                if(tolower(arg[0]) != 'f') usprintf(ftp.control,unsupp);
  948.                else usprintf(ftp.control,okay);
  949.                break;
  950.            case MODE_CMD:
  951.                if(tolower(arg[0]) != 's') usprintf(ftp.control,unsupp);
  952.                else usprintf(ftp.control,okay);
  953.                break;    
  954.            case DELE_CMD:
  955.                file = pathname(ftp.cd,arg);
  956.                if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file))
  957.                     usprintf(ftp.control,noperm);
  958.                else if(unlink(file) == 0)
  959.                {
  960.                    if(LogLevel>=5) AddLog("DELE %s by %s",file,ftp.username);
  961.                    usprintf(ftp.control,deleok);
  962.                } 
  963.                else usprintf(ftp.control,delefail,sys_errlist[errno]);
  964.                free(file);
  965.                break;
  966. //            case PASV_CMD:
  967. //                passive(&ftp);
  968. //                break;
  969.        }
  970.     }
  971.            
  972. finish:
  973.     free(ftp.username);
  974.     free(ftp.path);
  975.     free(ftp.cd);
  976.     
  977.     exit(0);
  978. }
  979.